package com.zhangzhan.blog_api.filter;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.zhangzhan.base.common_model.pojo.LoginUser;
import com.zhangzhan.base.common_model.result.ResponseResult;
import com.zhangzhan.base.enums.AppHttpCodeEnum;
import com.zhangzhan.base.exception.SystemException;
import com.zhangzhan.base.utils.JwtUtil;
import com.zhangzhan.base.utils.RedisCache;
import com.zhangzhan.base.utils.WebUtils;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

import static com.zhangzhan.base.constant.RedisKey.HEADER;
import static com.zhangzhan.base.constant.RedisKey.LOGIN_KEY;

/**
 * @author 张一恒
 * @version 1.0
 * @description: 前台登录认证过滤器
 * @date 2024/2/3 22:21
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private RedisCache redisCache;

    /**
     * Same contract as for {@code doFilter}, but guaranteed to be
     * just invoked once per request within a single request thread.
     * See {@link #shouldNotFilterAsyncDispatch()} for details.
     * <p>Provides HttpServletRequest and HttpServletResponse arguments instead of the
     * default ServletRequest and ServletResponse ones.
     *
     * @param request
     * @param response
     * @param filterChain
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException, SystemException {

//        ①定义Jwt认证过滤器获取token解析token获取其中的userid从
//        redis中获取用户信息存入SecurityContextHolder

        //从请求头中获取token信息
        String token = request.getHeader(HEADER);
        if (StrUtil.isBlank(token)) {
            //如果不需要登陆直接放行
            filterChain.doFilter(request, response);
        }

        //解析token获取user信息：用户id
        Claims jwt = null;
        try {
            jwt = JwtUtil.parseJWT(token);
        } catch (Exception e) {
            //过滤器没有到controller层异常信息不能被捕获
//            throw new RuntimeException(e);
            //进行渲染 写到响应体中

            //已增加认证失败处理器不需要这里再次响应
//            WebUtils.renderString(response, JSON.toJSONString(ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN)));
            return;
        }

        //去redis读取用户信息
        LoginUser loginUser = redisCache.getCacheObject(LOGIN_KEY + jwt.getSubject());
        if (Objects.isNull(loginUser)) {
            WebUtils.renderString(response, JSON.toJSONString(ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_ERROR)));
            return;
        }


        //存入SecurityContextHolder 主要获取用户信息使用
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,null);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        filterChain.doFilter(request, response);
    }
}
